﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;


namespace SprayingRobot.Test
{
    #region 包装类
    public interface IApi
    {

    }

    public class 测试引用类型
    {
        public string S7 { get; set; }

        public int S8 { get; set; }
    }


    public interface ITest : IApi
    {
        Task<string> GetTestResultAsync(string name, int number);

        Task<int> GetTestResultAsyncCCC(string name);

        void GetTestResult(string name);

        Task<string> GetTestResult(测试引用类型 name, int number);

        Task<string> GetTestResult(string name, int number);



        //string GetTestResult(string name);
    }

    public class IPadTestApiYYF : ITest
    {
        public void GetTestResult(string name)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetTestResult(string name, int number)
        {
            throw new NotImplementedException();
        }

        public void GetTestResult(测试引用类型 name)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetTestResult(测试引用类型 name, int number)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetTestResultAsync(string name, int number)
        {
            throw new NotImplementedException();
        }

        public Task<int> GetTestResultAsyncCCC(string name)
        {
            throw new NotImplementedException();
        }

        //Task<string> ITest.GetTestResult(测试引用类型 name)
        //{
        //    throw new NotImplementedException();
        //}
    }

    public class ApiResult
    {
        public T GetValue<T>() where T : Task
        {
            return null;
        }

        //public 
    }

    public class ApiResult<T> : ApiResult
    {
        public T Value { get; set; }

        public T GetValue()
        {
            return Value;
        }

        public Task<F> GetValue<F>()
        {
            return null;
        }


    }

    public class TaskApiResult<T> : ApiResult where T : Task
    {

    }
    #endregion


    public class 测试
    {
        /// <summary>
        /// 测试洗枪频率
        /// </summary>
        public static void 测试洗枪频率()
        {
            Type typeExpression = typeof(Expression);
            Type[] types = new Type[] { typeExpression ,typeof(ParameterExpression[]) };

            //MethodInfo methodInfo = typeExpression.GetMethod(nameof(Expression.Lambda),  BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
            //MethodInfo methodInfo = typeExpression.GetMethod(nameof(Expression.Lambda),  types);

            MethodInfo methodInfo = typeExpression.GetMethod(nameof(Expression.Lambda),1, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static, null,types,null);
            //MethodInfo methodInfo = typeExpression.GetMethod(nameof(Expression.Lambda), BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static, types);
            //GetMethod(string name, int genericParameterCount, BindingFlags bindingAttr, Binder ? binder, Type[] types, ParameterModifier[] ? modifiers)
            // MethodInfo[] methodInfos = typeExpression.GetMethods(");
            //var cdd=  methodInfo.MemberType;
            //typeExpression.MA
            //int i = 0;
            //int j = 1;
            //bool result = MainWindowVM.Instance.GetIsNeedWashZhenShi(i, j);
            //Proxy<ITest>.Excute5(x => x.GetTestResultAsync(null, 30));

            测试引用类型 test测试引用类型 = new 测试引用类型() { S7 = "111", S8 = 123 };
            Proxy<ITest>.Excute5(x => x.GetTestResult(test测试引用类型,25));
            var d= Proxy<ITest>.Excute5(x => x.GetTestResultAsync(null, 30));

            var c = Proxy<ITest>.Excute5(x => x.GetTestResultAsync(null, 30).Result);
            //var dddd= c.GetValue<Task<string>, string>();
           
            Proxy<ITest>.Excute5(x => x.GetTestResultAsyncCCC("1"));
            Proxy<ITest>.Excute5(x => x.GetTestResultAsyncCCC("1"));
            Proxy<ITest>.Excute5(x => x.GetTestResult("1"));
            Proxy<ITest>.Excute5(x => x.GetTestResult("1",20));
            Proxy<ITest>.Excute6(x => x.GetTestResultAsync(null, 30));



            Proxy.ExcuteT3<ITest, Task<string>>(x => x.GetTestResultAsync("1", 30));
            Proxy.ExcuteT3<ITest, Task<int>>(x => x.GetTestResultAsyncCCC("1"));




           ApiResult<Task<string>> apiResult= Proxy.ExcuteT4<ITest, Task<string>>(x => x.GetTestResultAsync("1", 30));



            //Proxy.ExcuteT3<IPadTestApiYYF, Task<string>>(x => x.GetTestResultAsync("1", 30));

            //Proxy.ExcuteT2<IPadTestApiYYF, Task<string>>(x => x.GetTestResultAsync("1", 30));

            //Proxy<IPadTestApiYYF>.ExcuteT2(x=>x.GetTestResultAsync("1",30));
        }


       


        public static void ExcuteT<T1, T2, T3>(Func<T1, T2, T3> func, T1 t1, T2 t2)
        {
            MethodInfo methodInfo = func.Method;
        }

        public static void ExcuteT2<T1, T2, T3>(Func<T1, T2, T3> func, T1 t1, T2 t2)
        {
            MethodInfo methodInfo = func.Method;
        }

    }

    public class Proxy<T> where T : IApi
    {
        public static TaskApiResult<F> Excute6<F>(Expression<Func<T, F>> expression)where F:Task
        {
            Type type = expression.Body.GetType();

            var bodyExpression = (MethodCallExpression)expression.Body;
            var lis = bodyExpression.Arguments;
            Type type2 = lis[0].GetType();
            MethodInfo methodInfo = bodyExpression.Method;
            object[] objects = new object[lis.Count];
            for (int i = 0; i < lis.Count; i++)
            {
                ConstantExpression constantExpression = lis[i] as ConstantExpression;
                objects[i] = constantExpression.Value;
            }

            return null;
        }

        public static ApiResult<F> Excute5<F>(Expression<Func<T, F>> expression)
        {
            Type type = expression.Body.GetType();
            MethodInfo methodInfo;
            MethodCallExpression bodyExpression;
            switch (expression.Body.NodeType)
            {
                case ExpressionType.MemberAccess:
                    MemberExpression bodyMemberExpression = (MemberExpression)expression.Body;
                    bodyExpression = bodyMemberExpression.Expression as MethodCallExpression;
                    methodInfo = bodyExpression.Method;
                    break;
                case ExpressionType.Call:
                     bodyExpression = (MethodCallExpression)expression.Body;
                     methodInfo = bodyExpression.Method;
                    break;
                default:
                    throw new Exception($"表达式错误{expression}");
                    break;
            }



            object[]? args;
            try
            {
                args = (from arg in bodyExpression.Arguments
                    select Expression.Lambda<Func<object>>(arg, null)
                        .Compile()()).ToArray();
            }
            catch (Exception e)
            {
                //return new ApiResult<F>(false, "获取表达式值出现异常");
            }

            var lis = bodyExpression.Arguments;
            Type type2 = lis[0].GetType();
            object[] objects = new object[lis.Count];
            for (int i = 0; i < lis.Count; i++)
            {
               
                //Type typeFunc=typeof(Func).MakeGenericType(types);

                switch (lis[i].NodeType)
                {
                    case ExpressionType.Constant:
                        ConstantExpression constantExpression = lis[i] as ConstantExpression;
                        objects[i] = constantExpression.Value;
                        var result1 = GetObjFormExpressionArgument(lis[i]);
                        break;
                    case ExpressionType.MemberAccess:
                        MemberExpression memberExpression = (MemberExpression)lis[i];
                        


                        objects[i]=  Expression.Lambda<Func<object>>(lis[i], null)
                            .Compile()();
                        var result2= GetObjFormExpressionArgument(lis[i]);
                        #region 反射执行

                        var typeFunc = typeof(Func<object>);
                        //Type CCC = typeof(Func);
                      
                        Type typeExpression = typeof(Expression);
                        Type[] types = new Type[] { typeExpression, typeof(ParameterExpression[]) };
                        MethodInfo lambdaMethodInfo = typeExpression.GetMethod(nameof(Expression.Lambda), 1, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static, null, types, null);
                        dynamic ex = lis[i];
                        Type typeArgument = ex.Type;
                        Type funcArgument=GetFuncType(typeArgument);
                        var realMethod= lambdaMethodInfo.MakeGenericMethod(funcArgument);
                       var  dddInvoke=realMethod.Invoke(null, new object?[]{ lis[i],null });
                        dynamic expressionFuncArgument = dddInvoke;
                        
                        var result3= expressionFuncArgument.Compile()();

                        Expression < Func<object> > ddd = dddInvoke as Expression<Func<object>>;
                        var result = ddd?.Compile()();
                        #endregion
                        Type delegrateType = typeof(Func<object>);

                        //objects[i] = Expression.Lambda(delegrateType, lis[i], null)
                        //    .Compile()();
                        //FieldExpression
                        //System.Linq.Expressions.FieldExpression

                        break;
                }
               
            }

            return null;
        }

        public static object GetObjFormExpressionArgument(Expression exception)
        {
            Type typeExpression = typeof(Expression);
            Type[] types = new Type[] { typeExpression, typeof(ParameterExpression[]) };
            MethodInfo lambdaMethodInfo = typeExpression.GetMethod(nameof(Expression.Lambda), 1, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static, null, types, null);
            dynamic ex = exception;
            Type typeArgument = ex.Type;
            Type funcArgument = GetFuncType(typeArgument);
            var realMethod = lambdaMethodInfo.MakeGenericMethod(funcArgument);
            var dddInvoke = realMethod.Invoke(null, new object?[] { exception, null });
            dynamic expressionFuncArgument = dddInvoke;

            var result2 = expressionFuncArgument.Compile()();
            return result2;
        }



        public static ApiResult Excute5(Expression<Action<T>> expression)
        {
            Type type = expression.Body.GetType();

            var bodyExpression = (MethodCallExpression)expression.Body;
            var lis = bodyExpression.Arguments;
            Type type2 = lis[0].GetType();
            MethodInfo methodInfo = bodyExpression.Method;
            object[] objects = new object[lis.Count];
            for (int i = 0; i < lis.Count; i++)
            {
                ConstantExpression constantExpression = lis[i] as ConstantExpression;
                objects[i] = constantExpression.Value;
            }

            return null;
        }

        public static Type GetFuncType(Type type)
        {
            Type type1 = typeof(Func<int>);
            Type typeFunc = type1.GetGenericTypeDefinition();
            var typeResult = typeFunc.MakeGenericType(type);
            return typeResult;
        }
    }

    public class Proxy
    {
        //public static void ExcuteT2<T,F>(Expression<Func<T, Func<T1, T2, T3>>> expression, T1 t1, T2 t2)
        //{
        //    Type type1 = typeof(ITest);
        //    MethodInfo methodInfo = type1.GetMethod(nameof(ITest.GetTestResultAsync));
        //    var bodyExpression = expression.Parameters[0];
        //    //dynamic propertyName = bodyExpression.Type.De
        //    string name = PropertyHelp.GetPropertyName(expression);


        //    //MethodInfo methodInfo = func.Method;
        //}

        public static void ExcuteT2<T,F>(Func<T, F> expression)
        {
            //throw new NotImplementedException();
        }

        public static void ExcuteT3<T, F>(Expression<Func<T, F>> expression)
        {
            Type type = expression.Body.GetType();

            var bodyExpression = (MethodCallExpression)expression.Body;
            var lis=bodyExpression.Arguments;
            Type type2 = lis[0].GetType();
            MethodInfo methodInfo = bodyExpression.Method;
            object[] objects = new object[lis.Count];
            for (int i = 0; i < lis.Count; i++)
            {
                ConstantExpression constantExpression= lis[i] as ConstantExpression;
                objects[i]= constantExpression.Value;
            }

            //bodyExpression.

            //throw new NotImplementedException();
        }

        public static ApiResult<F> ExcuteT4<T, F>(Expression<Func<T, F>> expression)
        {
            Type type = expression.Body.GetType();

            var bodyExpression = (MethodCallExpression)expression.Body;
            var lis = bodyExpression.Arguments;
            Type type2 = lis[0].GetType();
            MethodInfo methodInfo = bodyExpression.Method;
            object[] objects = new object[lis.Count];
            for (int i = 0; i < lis.Count; i++)
            {
                ConstantExpression constantExpression = lis[i] as ConstantExpression;
                objects[i] = constantExpression.Value;
            }

            return null;
            //bodyExpression.

            //throw new NotImplementedException();
        }
    }
}
